(function(global,factory){
    typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
    typeof define === 'function' && define.amd ? define(factory) :
    (global = global || self, global.dialog = factory());
}(this,function(){
    const dftSetting = {
        isEnableShade:true
        ,isEnableTitle:true
        ,closeShade:true
        ,title:'标题'
        ,skin:''
        ,content:""
        ,btns:[]
        ,createBefore:function(){}
        ,createAfter:function(){}
    }
    ,template = {
        escape:{
            "'":"'",
            "\\n":"\\n",
            "\\r":"\\r",
            "\\":"\\"
        }
        ,reg:/'|\\n|\\r|\\/g
    };

    let $ = function(selector,context=document){
        return new InitDOM(selector,context);
    }

    , InitDOM = function(selector,context){
        if(!selector){return this}
        this.context = context;
        this.selectorTypeMatch[selector.nodeType ? 'el' : typeof(selector)].call(this,selector);
        return this;
    }
    ,CustomEvt = function(){
        this.subEvents = {};
    };

    $.each = function(set,callback){
        Array.prototype.forEach.call(set,function(el,i){
            callback.call(el,el,i)
        })
        return set;
    }

    InitDOM.prototype = $.prototype = Object.create(Array.prototype);

    Object.assign($.prototype,{
        constructor:$,
        //选择器类型匹配器
        selectorTypeMatch:{
            string(selector){
                this.selector = selector;
                this.mergeDOM($(this.context).find(selector));
            }
            ,object(selector){
                this.mergeDOM(selector);
            }
            ,el(selector){
                this[0] = selector
                this.length = 1;
            }
        }
        ,mergeDOM(nodeList){
            Object.assign(this,nodeList)
            this.length = nodeList && nodeList.length || 0;
        }
        ,each(callback){
            return $.each(this,callback);
        }
        ,find(selector){
            let doms = [];
            this.each(function(){
                let dom = this.querySelectorAll(selector);
                doms.push(Array.from(dom));
            })
            return $($.utils.flatArr(doms));
        }
        ,animateEnd(type='animation',sucHandle){
            return this.each(function(){
                $.utils.animateEnd(this,type,sucHandle)
            });
        }
        ,append(html){
            let self = this;
            self.appendChilds = [];
            if(typeof html == 'string'){
                self.each(function(){
                    let fragment = document.createDocumentFragment()
                    , tempEl = document.createElement('div')
                    tempEl.innerHTML = html;
                    while(tempEl.firstChild){
                        fragment.appendChild(tempEl.firstChild)
                    }
                    let nodeList = Object.assign({},fragment.childNodes);
                    nodeList.length = Object.keys(nodeList).length;
                    self.appendChilds.push(nodeList);
                    this.appendChild(fragment);
                });
            }else{
                self.appendChilds.push(html);
                self.appendChild(html);
            }
            return self;
        }
    });

    CustomEvt.prototype = {
        constructor:CustomEvt
        ,$emit:function(event,data){
            event = this.subEvents[event];
            if(event){
                for(let i = 0; i < event.length; i++){
                    event[i].apply(this, data);
                }
            }
            return this;
        }
        ,$on:function(event,handle){
            let subEvents = this.subEvents;
            !(event in subEvents) && (subEvents[event] = [])
            subEvents[event].push(handle);
            return this;
        }
        ,$off:function(event,handle){
            let events = this.subEvents[event];
            if(!handle){
                events && delete Reflect.deleteProperty(this.subEvents, event);
            }else{
                if(typeof handle == 'function' && events){
                    for(let i = 0,len = events.length; i < len; i++){
                        let event = events[i];
                        if(event == handle){
                            return events.splice(i,1);
                        }
                    } 
                }
            }
            return this;
        }
    }

    let dialog = function(options={}){
        return new Layer(options);
    }

    dialog.utils = {
        flatArr(arr){
            let newArr = [];
            arr.forEach(item=>{
                if(Array.isArray(item) || item instanceof NodeList){
                    newArr = newArr.concat(dialog.utils.flatArr(item))
                }else{
                    newArr.push(item);
                }
            })
            return newArr;
        }
        ,animateEnd(ele,type,sucHandle){
            type = type || 'animation'
            //1、获取动画名
            let eventName = function(){
                const animateEvtNames = {
                    'animation': 'animationend',
                    'OAnimation': 'oAnimationEnd',
                    'MozAnimation': 'mozAnimationEnd',
                    'WebkitAnimation': 'webkitAnimationEnd'
                }
                , transitEvtNames = {
                    //chrome
                    WebkitTransition : 'webkitTransitionEnd',
                    //Firefox
                    MozTransition    : 'transitionend',
                    //Opera
                    OTransition      : 'oTransitionEnd otransitionend',
                    transition       : 'transitionend'
                }
                , animateName = (function(el) {
                    let animation = type == 'animation' ? animateEvtNames : transitEvtNames;
                    for (let t in animation) {
                        if (el.style[t] !== undefined) {
                            return animation[t];
                        }
                    }
                })(document.createElement('div'));
                return animateName;
            }();
            //2、给ele绑定动画结束的回调
            const animateEndEventListener = function(eventName,sucHandle){
                //在每次transitionEnd的事件后执行该函数
                const handleAniEnd = function(e){
                    ele.removeEventListener(eventName,handleAniEnd);
                    sucHandle.call(this,e,ele);
                };
                ele.addEventListener(eventName,handleAniEnd,false);
            }
            eventName && animateEndEventListener(eventName,sucHandle)
        }
        ,compile(tpl){
            tpl = tpl.replace(/[\s\t\r\n]+/g," ")
            .replace(/\{\{#\s*([\s\S]+?)\s*\}\}/g,"');$1__a.push('")
            .replace(/\{\{\s*([\s\S]+?)\s*\}\}/g,"');__a.push($1);__a.push('")
            tpl = "var __a = [];__a.push('"+tpl+"');return __a.join('')";
            tpl = tpl.replace(/__a.push\('([\S\s])*?'\)/g,(...arg)=>{
                return template.reg.test(arg[1]) ? arg[0].replace(arg[1],arg[1].replace(template.reg,arg=>"\\"+template.escape[arg])) : arg[0]
            })
            let compileFn = new Function("d",tpl);
            return (data)=>{
                return compileFn.call(this,data)
            }
        }
        ,arrayLike(arrLike){
            return Array.from ? Array.from(arrLike) : Array.prototype.slice.call(arrLike);;
        }
    }

    let Layer = function(options){
        this.options = Object.assign(dftSetting,options);
        this.init();
    }

    Layer.prototype = {
        constructor:Layer
        ,init:function(){
            let options = this.options;
            let create = this.createBefore(options.createBefore);
            this.createAfter.call(create,options.createAfter);
            create.call(this,function(){
                let $target = this.createLayer();
                this.animateHandler($target.appendChilds[0]);
            });
        }
        ,createBefore(callback){
            return this.create.before(function(){
                //this只跟调用者有关
                if(typeof callback == 'function'){
                    flag = callback.apply(this,arguments);
                }
                return flag;
            })
        }
        ,create(callback,retVal){
            retVal!=false && (retVal = callback.call(this))
            return retVal;
        }
        ,createLayer(){
            let html = [
                '{{# if(d.isEnableShade){ }}<div class="k-dialog-overlay"></div>{{# } }}',
                '<div class="k-dialog-wrapper {{d.skin}}">',
                    '<div class="k-dialog">',
                        '{{# if(d.isEnableTitle){ }}<div class="k-dialog-title">{{d.title}}</div>{{# } }}',
                        '<div class="k-dialog-body">{{d.content}}</div>',
                        '{{# if(d.btns && d.btns.length > 0){ }}',
                            '<div class="k-dialog-action">',
                                '{{# d.btns.forEach((btn,i)=>{ }}',
                                    '<button type="button" class="k-dialog-btn {{# btn.classes.forEach(skin=>{ }}{{skin}}{{# }); }}">{{btn.name}}</button>',
                                '{{# }); }}',
                            '</div> ',
                        '{{# } }}',
                    '</div>',
                '</div>'
            ].join('');
            let render = dialog.utils.compile(html);
            return $(document.body).append(render(this.options));
        }
        ,createAfter(callback){
            return this.after(function(){
                //this只跟调用者有关
                if(typeof callback == 'function'){
                    callback.apply(this,arguments);
                }
            })
        }
        ,animateHandler(els,enterClasses,enterToClasses){
            let dialogEl = els[els.length-1];
            if(this.options.isEnableShade){
                els[0].classList.add('k-dialog-overlay-enter');
                els[0].classList.add('k-dialog-overlay-transition-enter')
            }
            dialogEl.classList.add('k-dialog-enter');
            dialogEl.classList.add('k-dialog-transition-enter');            
            setTimeout(()=>{
                els[els.length-1].classList.remove('k-dialog-enter');
                els[els.length-1].classList.add('k-dialog-enter-to');
                if(this.options.isEnableShade){
                    els[0].classList.remove('k-dialog-overlay-enter');
                    els[0].classList.add('k-dialog-overlay-enter-to')
                } 
            },90);  
        }
    }

    //$.utils依赖(继承)于dialog.utils
    $.utils = dialog.utils;

    //数据注入
    dialog.$ = $;

    dialog.CustomEvt = CustomEvt;

    return dialog;

}));